//
// Created by lingzhitech on 25-8-14.
//
#include <deque>
#include <forward_list>
#include <list>
#include <gtest/gtest.h>

#include "../material/HandleInput.h"


bool searchValue(std::vector<int>::const_iterator begin, std::vector<int>::const_iterator end, int value) {
    while (begin != end) {
        if (*begin == value) {
            return true;
        }
        ++begin;
    }
    return false;
}

std::vector<int>::const_iterator searchValuePro(std::vector<int>::const_iterator begin,
                                                std::vector<int>::const_iterator end, int value) {
    while (begin != end) {
        if (*begin == value) {
            return begin;
        }
        ++begin;
    }
    //说明此时begin == end
    return end;
}

TEST(ch9, exercise0904) {
    std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    bool isFind = searchValue(data.cbegin(), data.cend(), 23);
    std::cout << "isFind = " << isFind << std::endl;
}

TEST(ch9, exercise0905) {
    std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::vector<int>::const_iterator location = searchValuePro(data.cbegin(), data.cend(), 3);
    std::cout << "location = " << location - data.cbegin() << std::endl;
}

TEST(ch9, exercise0911) {
    std::vector<int> data1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::vector<int> data2{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::vector<int> data3(data1);
    std::vector<int> data4;
    std::vector<int> data5 = data2;
    std::vector<int> data6{};
    std::vector<int> data7 = {};
    std::vector<int> data8(10, 42);
    std::vector<int> data9(10);
    std::vector<int> data10(data1.begin(), data1.end());
}

TEST(ch9, exercise0913) {
    std::list<int> lst = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::vector<double> newlst(lst.begin(), lst.end());
    for (double integer: newlst) {
        std::cout << integer << " ";
    }

    std::vector<int> v_int = {1, 2, 3, 4, 5};
    std::vector<double> v_double(v_int.begin(), v_int.end());
}

bool compareVectors(const std::vector<int> &v1, const std::vector<int> &v2) {
    return v1 == v2;
}

bool compareVector_List(const std::list<int> &l, const std::vector<int> &v) {
    const std::vector<int> l_copy(l.begin(), l.end());
    return l_copy == v;
}

TEST(ch9, exercise0915) {
    std::vector<int> data1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::vector<int> data2 = {1, 2, 3, 4, 5, 6, 7, 8, 9,};
    std::cout << "is the same? " << compareVectors(data1, data2) << std::endl;
}

TEST(ch9, exercise0916) {
    std::list<int> data1 = {1, 2, 3, 4, 5, 6, 7, 8, 9,};
    std::vector<int> data2 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    std::cout << "is the same? " << compareVector_List(data1, data2) << std::endl;
}

void read_strings_into_deque_iterator_print() {
    std::string str;
    std::deque<std::string> deq;
    while (std::cin >> str) {
        deq.push_back(str);
    }
    for (std::deque<std::string>::const_iterator it = deq.cbegin(); it != deq.cend(); ++it) {
        std::cout << *it << " ";
    }
}

void read_strings_into_list_iterator_print() {
    std::string str;
    std::list<std::string> lst;
    while (std::cin >> str) {
        lst.push_back(str);
    }
    for (std::list<std::string>::const_iterator it = lst.cbegin(); it != lst.cend(); ++it) {
        std::cout << *it << " ";
    }
}

TEST(ch9, exercise0918) {
    handle_input("abc def gcc apple", read_strings_into_deque_iterator_print);
}

TEST(ch9, exercise0919) {
    handle_input("ttp wwe chc taaa", read_strings_into_list_iterator_print);
}

void separate_elements(const std::list<int> &lst) {
    std::deque<int> evens;
    std::deque<int> odds;
    for (auto integer: lst) {
        if (integer % 2) {
            odds.push_back(integer);
        } else {
            evens.push_back(integer);
        }
    }
    auto print_deque = [](const std::deque<int> &dq) {
        for (auto it = dq.cbegin(); it != dq.cend(); ++it) {
            if (it != dq.cbegin()) std::cout << " ";
            std::cout << *it;
        }
        std::cout << std::endl;
    };

    print_deque(evens);
    print_deque(odds);
}

TEST(ch9, exercise0920) {
    handle_input("abc def gcc apple", separate_elements, std::list<int>({1, 2, 3, 4, 5, 6, 7, 8, 9, 10}));
}

void add_particular_elements_to_vector(std::vector<int> &v, int val) {
    auto it = v.begin();
    auto mid = it + (v.size() / 2);
    auto distance = mid - it;
    while (it != mid) {
        if (*it == val) {
            it = v.insert(it, val * 2);
            ++it;
            distance++;
            mid = v.begin() + distance;
        }
        ++it;
    }
}

TEST(ch9, exercise0922) {
    std::vector<int> test{5, 1, 5, 1, 2, 3, 4};
    handle_input("abc def gcc apple", add_particular_elements_to_vector, test, 5);
    for (auto i: test) {
        std::cout << i << " ";
    }
}

TEST(ch9, exercise0924) {
    std::vector<int> test;
    // std::cout << test.front() << std::endl;//Process finished with exit code 139 (interrupted by signal 11:SIGSEGV)
    // std::cout << *test.begin() << std::endl;//Process finished with exit code 139 (interrupted by signal 11:SIGSEGV)
    // std::cout << test[0] << std::endl;//Process finished with exit code 139 (interrupted by signal 11:SIGSEGV)
    // std::cout << test.at(0) << std::endl;//C++ exception with description "vector::_M_range_check: __n (which is 0) >= this->size() (which is 0)" thrown in the test body.
    //也就是说只有at会报空指针异常，其余都会使得程序崩溃
}
void copy_into_vector_and_list_remove(int ia[], int size) {
    std::vector<int> v;
    std::list<int> l;
    for (int i = 0; i < size; ++i) {
        v.push_back(ia[i]);
        l.push_back(ia[i]);
    }
    auto vbegin = v.begin();
    while (vbegin != v.end()) {
        if (*vbegin % 2 == 0) {
            vbegin = v.erase(vbegin);
        }else {
            ++vbegin;
        }
    }
    auto lbegin = l.begin();

    while (lbegin != l.end()) {
        if (*lbegin % 2) {
            lbegin = l.erase(lbegin);
        }else {
            ++lbegin;
        }
    }
    for (auto it = l.begin(); it != l.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    for (auto it = v.begin(); it != v.end(); ++it) {
        std::cout << *it << " ";
    }
}
// Using the following definition of ia, copy ia
// into a vector and into a list. Use the single-iterator form of
// erase to remove the elements with odd values from your list
// and the even values from your vector.
TEST(ch9, exercise0926) {
    int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 };
    handle_input("abc", copy_into_vector_and_list_remove, ia, sizeof(ia)/sizeof(ia[0]));
}

TEST(ch9, exercise0927) {
    std::forward_list<int> flst = {0,1,2,3,4,5,6,7,8,9};
    auto prev = flst.before_begin(); // denotes element "off the start" of flst
    auto curr = flst.begin(); // denotes the first element in flst
    while (curr != flst.end()) { // while there are still elements to process
        if (*curr % 2) // if the element is odd
            curr = flst.erase_after(prev); // erase it and move curr
        else {
            prev = curr; // move the iterators to denote the next
            ++curr; // element and one before the next element
        }
    }
}

// Write a function that takes a
// forward_list<string> and two additional string arguments. The
// function should find the first string and insert the second
// immediately following the first. If the first string is not found,
// then insert the second string at the end of the list.

void forward_list_add_str(std::forward_list<std::string> &flst, const std::string &str1, const std::string &str2) {
    auto curr = flst.begin();
    auto prev = flst.before_begin();
    bool isFind = false;
    while (curr != flst.end()) {
        if (*curr == str1) {
            isFind = true;
            curr = flst.insert_after(curr, str2);
            ++prev;
        }
        ++curr;
        ++prev;
    }
    if (!isFind) {
        flst.insert_after(prev, str2);
    }
}
TEST(ch9, exercise0928) {
    std::forward_list<std::string> flst{"abc", "ttf", "wwk", "fwofjeo", "abc"};
    forward_list_add_str(flst, "abc", "def");
    for (auto i: flst) {
        std::cout << i << " ";
    }
}

TEST(ch9, exercise0929) {
    std::vector<int> v(25, 1);
    for (auto i: v) {std::cout << i << " ";}
    std::cout << std::endl;
    v.resize(100);
    for (auto i: v) {std::cout << i << " ";}
    std::cout << std::endl;
    v.resize(10);
    for (auto i: v) {std::cout << i << " ";}
}